package br.ufrn.engcomp.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import br.ufrn.engcomp.arq.GenericDAO;
import br.ufrn.engcomp.arq.PersistDB;

@Repository(value = "genericDAOHibernate")
public class GenericDAOHibernate implements GenericDAO, Serializable {

    @Autowired
    private SessionFactory sessionFactory;

    public GenericDAOHibernate(SessionFactory sessionFactory) {
	this.sessionFactory = sessionFactory;
    }

    public GenericDAOHibernate() {
    }

    private Session currentSession() {
	return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    public <T extends PersistDB> T findById(final Class<T> clazz, final int id) {
	try {
	    T object = (T) currentSession().get(clazz, id);
	    return object;
	} catch (HibernateException e) {
	    throw new RuntimeException(e);
	}
    }

    protected Criteria getCriteria(Class<? extends PersistDB> clazz) {
	return currentSession().createCriteria(clazz);
    }

    @SuppressWarnings("unchecked")
    public <T extends PersistDB> List<T> findByColumn(final Class<T> clazz,
	    final String column, final String param) {
	Criteria c = currentSession().createCriteria(clazz);
	c.add(Restrictions.eq(column, param));
	c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
	return c.list();
    }

    @SuppressWarnings("unchecked")
    public <T extends PersistDB> List<T> findAll(final Class<T> clazz) {
	Criteria c = currentSession().createCriteria(clazz);
	return c.list();
    }

    public void save(final PersistDB object) {
	currentSession().clear();
	currentSession().saveOrUpdate(object);
	currentSession().flush();
    }

    public void update(final PersistDB object) {
	currentSession().clear();
	currentSession().update(object);
	currentSession().flush();
    }

    public void updateNoFlush(final PersistDB object) {
	currentSession().clear();
	currentSession().update(object);
    }

    public void delete(PersistDB object) {
	currentSession().delete(object);
	currentSession().flush();
    }

}
